package com.iteaj.iot.server.dtu;

import com.iteaj.iot.AbstractProtocol;
import com.iteaj.iot.IotProtocolFactory;
import com.iteaj.iot.ProtocolType;
import com.iteaj.iot.message.DefaultMessageHead;
import com.iteaj.iot.server.ServerMessage;
import com.iteaj.iot.server.dtu.message.DtuMessage;
import io.netty.buffer.ByteBuf;

import java.util.Objects;

public class DefaultDtuMessageAware<M extends ServerMessage> implements DtuMessageAware<M> {

    private DtuMessageDecoder<M> decoder;

    public DefaultDtuMessageAware() { }

    public DefaultDtuMessageAware(DtuMessageDecoder decoder) {
        this.decoder = decoder;
    }

    /**
     * 自定义协议
     * @param message {@link #decodeBefore(String, byte[], ByteBuf)} 返回值
     * @param factory 协议工厂
     * @return 返回自定义协议
     */
    public AbstractProtocol customize(M message, IotProtocolFactory<M> factory) {
        DefaultMessageHead head = (DefaultMessageHead) message.getHead();

        // Dtu获取设备编号的报文使用默认的协议来处理{@link DtuDeviceSnProtocol}
        if(head != null) {
            // 设备编号注册
            if(head.getType() == DtuCommonProtocolType.DEVICE_SN) {
                return this.getDeviceSnRegisterProtocol(message);

                // 心跳包适配
            } else if(head.getType() == DtuCommonProtocolType.HEARTBEAT) {
                return this.getHeartbeatProtocol(message);

                // AT指令适配
            } else if(head.getType() == DtuCommonProtocolType.AT) {
                return (AbstractProtocol) factory.remove(head.getMessageId());
            }

        }

        return null;
    }

    /**
     * 返回DTU设备注册设备编号协议
     * @param message
     * @return
     */
    protected AbstractProtocol getDeviceSnRegisterProtocol(M message) {
        return new DtuDeviceSnProtocol(message);
    }

    /**
     * 返回DTU设备心跳协议
     * @param message
     * @return
     */
    protected AbstractProtocol getHeartbeatProtocol(M message) {
        return new DtuHeartbeatProtocol(message);
    }

    /**
     * 在下一个解码器解析之前调用
     * @param equipCode 设备编号
     * @param message 已经读取的报文 {@link ByteBuf#slice()}
     * @param msg 源报文对象
     * @return return null会继续解码 而如果return M不继续解码直接做业务处理
     */
    public M decodeBefore(String equipCode, byte[] message, ByteBuf msg) {
        String strMsg = resolveHeartbeat(message);
        if(strMsg.length() == equipCode.length()) {
            // 包的内容和设备编号相同说明是心跳包
            if(Objects.equals(equipCode, strMsg)) {
                M heartMessage = createMessage(message);
                if(heartMessage instanceof DtuMessage) {
                    ((DtuMessage) heartMessage).setEquipCode(equipCode);

                    // 心跳协议
                    ((DtuMessage) heartMessage).setProtocolType(DtuCommonProtocolType.HEARTBEAT);
                }

                return heartMessage;
            }
        }
        ProtocolType customizeType;
        // 如果是At指令的响应
        if(isAt(equipCode, message, msg)) {
            M atMessage = createMessage(message);
            if(atMessage instanceof DtuMessage) {
                ((DtuMessage) atMessage).setEquipCode(equipCode);
                ((DtuMessage) atMessage).setProtocolType(DtuCommonProtocolType.AT);
            }

            return atMessage;

            // 自定义协议处理
        } else if((customizeType = customizeType(equipCode, message, msg)) != null) {
            M customizeMessage = createMessage(message);
            if(customizeMessage instanceof DtuMessage) {
                ((DtuMessage) customizeMessage).setEquipCode(equipCode);
                ((DtuMessage) customizeMessage).setProtocolType(customizeType);
            }

            return customizeMessage;
        }

        return null;
    }

    protected M createMessage(byte[] message) {
        return getDecoder().createMessage(message);
    }

    /**
     * 释放是AT指令
     * @param message
     * @return
     */
    protected boolean isAt(String equipCode, byte[] message, ByteBuf msg) {
        return false;
    }

    /**
     * 自定义类型
     * @param equipCode
     * @param message
     * @param msg
     * @return
     */
    protected ProtocolType customizeType(String equipCode, byte[] message, ByteBuf msg) {
        return null;
    }

    public DtuMessageDecoder<M> getDecoder() {
        return decoder;
    }

    public void setDecoder(DtuMessageDecoder<M> decoder) {
        this.decoder = decoder;
    }
}
